package com.chaos.auth.helper;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.chaos.auth.api.dto.wechat.WeChatPublicLoginResData;
import com.chaos.auth.api.dto.wechat.WeChatUserPhoneResponseData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;

@Deprecated
@Slf4j
public class WeixinHelper {
    static protected Logger logger = LoggerFactory.getLogger(WeixinHelper.class);
    /**
     * 获取code的请求地址*
     */
    public static String Get_Code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=STAT#wechat_redirect";

    /**
     * 获取Web_access_token https的请求地址*
     */
    public static String Web_access_tokenhttps = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

    /**
     * 获取Web_refresh_token的请求地址*
     */
    public static String Web_refresh_tokenhttps = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s";

    /**
     * 获取公众号access_token的请求地址*
     */
    public static String web_access_token = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    public static String WEB_URL_SCHEME_GENERATE = "https://api.weixin.qq.com/wxa/generatescheme?access_token=%s";

    public static String WEB_JSCODE2SESSION_TOKEN = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";

    /**
     * 获取公众号ticket的请求地址*
     */
    public static String web_ticket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";

    /**
     * 拉取用户信息的请求地址*
     */
    public static String User_Message = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s";

    /**
     * 订阅号拉去用户信息的请求地址，涉及订阅号是否关注的字段属性*
     */
    public static String User_Message_Subscribe = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN";

    /**
     * 创建二维码*
     */
    public static String cqrcode = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s";

    /**
     * 换取维码*
     */
    public static String qrcode = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";

    /**
     * 获取手机号
     */
    public static String phone_url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";

    // 替换字符串
    public static String getUserMessage(String accessToken, String openid) {
        return String.format(User_Message, accessToken, openid);
    }

    public static String getUserMessageSubscribe(String accessToken, String openid) {
        return String.format(User_Message_Subscribe, accessToken, openid);
    }

    // 替换字符串
    public static String createQRcode(String accessToken) {
        return String.format(cqrcode, accessToken);
    }


    // 替换字符串
    public static String getQRcode(String ticket) {
        return String.format(qrcode, ticket);
    }

    /**
     * 获取code的请求地址
     *
     * @param appId
     * @param redirectUrl
     * @param scope
     * @return code的请求地址
     */
    public static String getCode(String appId, String redirectUrl, String scope) {
        // 替换字符串
        return String.format(Get_Code, appId, redirectUrl, scope);
    }

    /**
     * 获取Web_access_tokenhttps的请求地址
     *
     * @param appId
     * @param secret
     * @param code
     * @return access_token的请求地址
     */
    public static String getWebAccess(String appId, String secret, String code) {
        // 替换字符串
        return String.format(Web_access_tokenhttps, appId, secret, code);
    }

    /**
     * 获取Web_access_tokenhttps的请求地址
     *
     * @param token
     * @return access_token的请求地址
     */
    public static String getPhone(String token) {
        // 替换字符串
        return String.format(phone_url, token);
    }

    /**
     * 获取Web_access_tokenhttps的请求地址
     *
     * @param appid
     * @param secret
     * @param code
     * @return access_token的请求地址
     */
    public static String getWebJsCode2SessionAccess(String appid, String secret, String code) {
        // 替换字符串
        return String.format(WEB_JSCODE2SESSION_TOKEN, appid, secret, code);
    }


    /**
     * 获取refresh_token的请求地址
     *
     * @param appid
     * @param refreshToken
     * @returnrefresh_token的请求地址
     */
    public static String getWebRefresh(String appid, String refreshToken) {
        // 替换字符串
        return String.format(Web_refresh_tokenhttps, appid, refreshToken);
    }

    /**
     * 获取WebAccessToken的请求地址
     *
     * @param appid
     * @param secret
     * @returnrefresh_token的请求地址
     */
    public static String getWebAccessToken(String appid, String secret) {
        // 替换字符串
        return String.format(web_access_token, appid, secret);
    }

    /**
     * 获取web_ticket的请求地址
     *
     * @param accessToken
     * @return web_ticket的请求地址
     */
    public static String getWebTicket(String accessToken) {
        // 替换字符串
        return String.format(web_ticket, accessToken);
    }


    /**
     * 获取客户端ip
     *
     * @param request
     * @return IP
     */
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            //多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = ip.indexOf(",");
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            return ip;
        }
        return request.getRemoteAddr();
    }

    /**
     * 动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容由于收银宝加字段而引起的签名异常
     *
     * @param request
     * @return
     */
    private TreeMap<String, String> getParams(HttpServletRequest request) {
        TreeMap<String, String> map = new TreeMap<String, String>();
        Map reqMap = request.getParameterMap();
        for (Object key : reqMap.keySet()) {
            String value = ((String[]) reqMap.get(key))[0];
            System.out.println(key + ";" + value);
            map.put(key.toString(), value);
        }
        return map;
    }

    /**
     * 以https方式发送请求并将请求响应内容以String方式返回
     *
     * @param path   请求路径
     * @param method 请求方法
     * @param body   请求数据体
     * @return 请求响应内容转换成字符串信息
     */
    public static String httpsRequestToString(String path, String method, String body) {
        if (path == null || method == null) {
            return null;
        }

        String response = null;
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        HttpsURLConnection conn = null;
        try {
            // 创建SSLConrext对象，并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new JEEWeiXinX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new SecureRandom());

            // 从上述对象中的到SSLSocketFactory
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            System.out.println(path);

            URL url = new URL(path);
            conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);

            //设置请求方式（git|post）
            conn.setRequestMethod(method);

            //有数据提交时
            if (null != body) {
                OutputStream outputStream = conn.getOutputStream();
                outputStream.write(body.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            inputStream = conn.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            response = buffer.toString();
        } catch (Exception e) {

        } finally {
            if (conn != null) {
                conn.disconnect();
            }
            try {
                bufferedReader.close();
                inputStreamReader.close();
                inputStream.close();
            } catch (IOException execption) {

            }
        }
        return response;
    }

    /**
     * 方法名：httpRequest</br>
     * <p>
     * 详述：发送http请求</br>
     *
     * @param requestUrl
     * @param requestMethod
     * @param outputStr
     * @return 说明返回值含义
     */
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            TrustManager[] tm = {new JEEWeiXinX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new SecureRandom());
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);
            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            httpUrlConn.setRequestMethod(requestMethod);
            if ("GET".equalsIgnoreCase(requestMethod)) {
                httpUrlConn.connect();
            }
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            jsonObject = JSONObject.parseObject(buffer.toString());
        } catch (ConnectException ce) {
        } catch (Exception e) {
        }
        return jsonObject;
    }

    /**
     * 方法名：byteToHex</br>
     * <p>
     * 详述：字符串加密辅助方法 </br>
     *
     * @param hash
     * @return 说明返回值含义
     */
    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    /**
     * 排序
     */
    public static String sort(String token, String timestamp, String nonce) {
        String[] strArray = {token, timestamp, nonce};
        Arrays.sort(strArray);

        StringBuilder sbuilder = new StringBuilder();
        for (String str : strArray) {
            sbuilder.append(str);
        }

        return sbuilder.toString();
    }

    public static String SHA1(String decript) {
        try {
            MessageDigest digest = MessageDigest
                    .getInstance("SHA-1");
            digest.update(decript.getBytes());
            byte[] messageDigest = digest.digest();
            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
        }
        return "";
    }

    /**
     * 微信支付结果
     *
     * @return
     */
    public static String getNotifyStr(HttpServletRequest request) {
        String notifyData = "";
        try {
            InputStream is = request.getInputStream();
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                notifyData = sb.toString();
                System.err.println(notifyData);
            } catch (IOException e) {
                logger.error("WXPayServiceImpl getNotifyStr  IOException message:{}, info", e.getMessage(), e);
            } finally {
                is.close();
            }
        } catch (Exception e) {
            logger.error("获取回调数据异常:" + e.getMessage());
        }

        return notifyData;
    }

    /**
     * 将request中的参数转换成Map
     *
     * @param request
     * @return
     */
    public static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        //获取支付宝POST过来反馈信息
        Map<String, String> retMap = new HashMap<>(16);

        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();

        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;

            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }

        return retMap;
    }


    public static WeChatPublicLoginResData weChatPublicUserLogin(String url) {
        log.info("WechatHelper  weChatPublicUserLogin requestUrl :{},", url);
        String wxResponse = HttpUtil.get(url, Collections.emptyMap());
        log.info("WechatHelper  weChatPublicUserLogin res :{},", wxResponse);
        WeChatPublicLoginResData weChatPublicLoginResData = null;
        if (StrUtil.isNotBlank(wxResponse)) {
            try {
                weChatPublicLoginResData = JSON.parseObject(wxResponse, WeChatPublicLoginResData.class);
            } catch (Exception e) {
                log.error("failed to parse the wx response", e);
            }
        }
        return weChatPublicLoginResData;
    }

    public static WeChatUserPhoneResponseData weChatGetPhoneNumber(String url, String code) {
        Map<String,Object> paramMap = Maps.newHashMap();
        paramMap.put("code", code);
        log.info("WechatHelper  weChatGetPhoneNumber requestUrl :{},", paramMap);
        String wxResponse = httpsRequestToString(url,"POST",JSON.toJSONString(paramMap));
        log.info("WechatHelper  weChatGetPhoneNumber res :{},", wxResponse);
        WeChatUserPhoneResponseData weChatUserPhoneResponseData = null;
        if (StrUtil.isNotBlank(wxResponse)) {
            try {
                weChatUserPhoneResponseData = JSON.parseObject(wxResponse, WeChatUserPhoneResponseData.class);
            } catch (Exception e) {
                log.error("failed to parse the wx response", e);
            }
        }
        return weChatUserPhoneResponseData;
    }

}
